home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / prof / sun3.md / _mcount.c next >
C/C++ Source or Header  |  1990-10-19  |  6KB  |  213 lines

  1. /* 
  2.  * _mcount.c --
  3.  *
  4.  *    This is the code for the routine mcount.  mcount is the routine
  5.  *    called at the beginning of each procedure if it the code has
  6.  *    been compiled with the -p option to cc.
  7.  *
  8.  *    NB: The compiler compiles this procedure into something called
  9.  *    "_mcount" which we massage back into "mcount" (see the Makefile).
  10.  *
  11.  * Copyright 1985 Regents of the University of California
  12.  * All rights reserved.
  13.  */
  14.  
  15. #ifndef lint
  16. static char rcsid[] = "$Header: /sprite/src/kernel/prof/sun3.md/RCS/_mcount.c,v 9.2 90/10/19 15:53:08 rab Exp $ SPRITE (Berkeley)";
  17. #endif not lint
  18.  
  19.  
  20. #include <sprite.h>
  21. #include <stdio.h>
  22. #include <prof.h>
  23. #include <profInt.h>
  24. #include <sync.h>
  25. #include <sys.h>
  26. #include <dbg.h>
  27.  
  28. /*
  29.  * Boolean to prevent recursion in mcount.  This only works
  30.  * on a uniprocessor.  This is needed in case we call printf
  31.  * or a Sync_ routine from within mcount and those routines
  32.  * have been instrumented with calls to mcount.
  33.  */
  34. static Boolean inMcount = FALSE;
  35.  
  36. /*
  37.  * There is a critical section when mcount does a pseudo-alloc
  38.  * of the storage for its arcs.
  39.  */
  40.  
  41. static Sync_Semaphore    mcountMutex = Sync_SemInitStatic("mcountMutex");
  42.  
  43.  
  44. /*
  45.  *----------------------------------------------------------------------
  46.  *
  47.  * mcount --
  48.  *
  49.  *    A call to this routine is inserted by the compiler at the
  50.  *    beginning of every routine. (Use the -p option to cc.)
  51.  *    This looks up the call stack a bit to determine which arc
  52.  *    of the call graph is being executed.  A call graph arc represents
  53.  *    one routine calling another.  The routine with the call to mcount
  54.  *    is the callee of the arc, its caller (mcount's "grandparent")
  55.  *    is the caller of the arc.  An execution count is kept for each
  56.  *    arc.  The counts are dumped out and analyzed by the gprof program.
  57.  *
  58.  * Results:
  59.  *    None.
  60.  *
  61.  * Side effects:
  62.  *    Increment a counter corresponding to the call graph arc.
  63.  *
  64.  *----------------------------------------------------------------------
  65.  */
  66.  
  67. void
  68. mcount()
  69. {
  70.     register unsigned int calleePC;    /* PC of instr. that called mcount */
  71.     register unsigned int callerPC;    /* PC of instr. that called mcount's 
  72.                      * caller */
  73.     register unsigned int instructionNumber;    /* Index into profArcIndex */
  74.     register ProfRawArc *arcPtr;    /* Pointer to arc data storage */
  75.  
  76.     if (!profEnabled) {
  77.     return;
  78.     }
  79.  
  80.     if (inMcount) {
  81.     return;
  82.     } else {
  83.     inMcount = TRUE;
  84.     }
  85.  
  86.     /*
  87.      * Get the PC that was saved after the jsr mcount instruction.
  88.      * This is done by getting our frame pointer and then looking
  89.      * next to it on the stack for the saved PC.
  90.      * The saved PC identifies the caller of mcount and the callee
  91.      * of the call graph arc.
  92.      */
  93.  
  94.     calleePC  = Prof_ThisPC( Prof_ThisFP() );
  95.  
  96.  
  97.     /*
  98.      * Get the PC that was saved after the jsr foo instruction.
  99.      * This PC identifies the caller of foo and the caller in
  100.      * the call graph arc.
  101.      */
  102.  
  103.     callerPC = Prof_ThisPC( Prof_CallerFP() );
  104.  
  105.     /*
  106.      * Use the PC of the jsr foo instruction as an index into the
  107.      * index of stored arcs.  There should only be one call instruction
  108.      * that corresponds to the index.
  109.      *
  110.      * Go from PC to instruction number by subracting off the base
  111.      * PC and dividing by the instruction size (2 bytes).
  112.      */
  113.  
  114.     if (callerPC < (unsigned int)&spriteStart) {
  115.     /*
  116.      * The PC from the caller's frame is bad. This happens when a 
  117.      * new process is started. 
  118.      */
  119.     goto exit;
  120.     }
  121.  
  122.     instructionNumber = 
  123.         (callerPC - (unsigned int) &spriteStart) >> PROF_ARC_SHIFT;
  124.     if (instructionNumber > profArcIndexSize) {
  125.     printf("_mcount: PC %x: Index (%d) exceeds bounds (%d)\n",
  126.           callerPC, instructionNumber, profArcIndexSize);
  127.     goto exit;
  128.     }
  129.  
  130.     /*
  131.      * Check to see if arcPtr equals an unused value (which is 0 because
  132.      * profArcIndex is initialized with bzero in Prof_Start).
  133.      */
  134.  
  135.     arcPtr = profArcIndex[instructionNumber];
  136.     if (arcPtr == (ProfRawArc *) 0) {
  137.  
  138. #ifdef DEBUG
  139.     printf("mcount: 1 callerPC = %x(%d), calleePC = %x\n",
  140.                 callerPC, instructionNumber, calleePC);
  141.     /* DBG_CALL; */
  142. #endif DEBUG
  143.  
  144.     /*
  145.      * First time call graph arc has been traversed.  Allocate arc
  146.      * storage from the arcList and initialize it.  This is locked
  147.      * to prevent the scheduler from interrupting the allocation
  148.      * and initialization.
  149.      */
  150.  
  151.     if (profArcListFreePtr >= profArcListEndPtr) {
  152.         profEnabled = FALSE;
  153.         printf("_mcount: No more arcs, stopping profiling\n");
  154.     } else {
  155.  
  156.         MASTER_LOCK(&mcountMutex);
  157.         Sync_SemRegister(&mcountMutex);
  158.  
  159.         arcPtr = profArcListFreePtr;
  160.         profArcListFreePtr++;
  161.         profArcIndex[instructionNumber] = arcPtr;
  162.         arcPtr->calleePC = calleePC;
  163.         arcPtr->count    = 1;
  164.         arcPtr->link     = (ProfRawArc *)NIL;
  165.  
  166.         MASTER_UNLOCK(&mcountMutex);
  167.     }
  168.     goto exit;
  169.     }
  170.  
  171.     while (arcPtr->calleePC != calleePC) {
  172.     /*
  173.      * Loop through the list of callee's for this caller.
  174.      */
  175.  
  176.     if (arcPtr->link == (ProfRawArc *)NIL) {
  177.  
  178.         /*
  179.          *  Allocate, link, and initialize another arc storage unit.
  180.          */
  181. #ifdef DEBUG
  182.         printf("mcount 2 callerPC = %x(%d), calleePC = %x\n",
  183.             callerPC, instructionNumber, calleePC);
  184.     /* DBG_CALL; */
  185. #endif DEBUG
  186.  
  187.         if (profArcListFreePtr >= profArcListEndPtr) {
  188.         printf("_mcount: No more arcs\n");
  189.         } else {
  190.         MASTER_LOCK(&mcountMutex);
  191.  
  192.         arcPtr->link = profArcListFreePtr;
  193.         profArcListFreePtr++;
  194.  
  195.         arcPtr = arcPtr->link;
  196.         arcPtr->calleePC    = calleePC;
  197.         arcPtr->count        = 1;
  198.         arcPtr->link        = (ProfRawArc *) NIL;
  199.  
  200.         MASTER_UNLOCK(&mcountMutex);
  201.         }
  202.         goto exit;
  203.     }
  204.     arcPtr = arcPtr->link;
  205.     }
  206.     arcPtr->count++;
  207.  
  208. exit:
  209.  
  210.     inMcount = FALSE;
  211.     return;
  212. }
  213.